﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.ComponentModel.Composition.Hosting;

namespace Microsoft.ComponentModel.Composition.Extensions.Web
{
    public class MefControllerFactory : IControllerFactory
    {
        // private const string ControllerExportEntryName = "controllerExport";
        private readonly ScopedContainerManager _scopeManager;

        public MefControllerFactory(ScopedContainerManager scopeManager)
        {
            this._scopeManager = scopeManager;
        }

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            // TODO: Also filter by namespace (if available on the route)
            IEnumerable<string> namespaces = GetNamespaceFromRoute(requestContext);
            // ...

            
            var contextItems = requestContext.HttpContext.Items;
            var container = _scopeManager.GetRequestContainer(contextItems);

            var controllers = container.GetExports<IController, IDictionary<string, object>>();

            var controllerExport = controllers.
                Where(exp =>
                    exp.Metadata.ContainsKey(Constants.ControllerNameMetadataName) &&
                    exp.Metadata[Constants.ControllerNameMetadataName].ToString().ToLowerInvariant().Equals(controllerName.ToLowerInvariant())).
                    FirstOrDefault();

            if (controllerExport == null)
            {
                throw new HttpException(404, "Not found");
            }

            return controllerExport.Value;
        }

        public void ReleaseController(IController controller)
        {
            // Not required as container will be disposed when the request is ended
        }

        private static IEnumerable<string> GetNamespaceFromRoute(RequestContext requestContext)
        {
            object routeNamespacesObj;

            if (requestContext != null &&
                requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj))
            {
                return routeNamespacesObj as IEnumerable<string>;
            }

            return null;
        }
    }
}
